#include <functional>
#include <unistd.h>
#include <pthread.h>
#include <vector>
#include <iostream>
#include <sys/types.h>
#include <string.h>
#include <signal.h>
using namespace std;

void *ThreadTest1(void *arg)
{
    const char *threadName = (const char *)arg;
    while (1)
    {
        cout << "i am a new thread, mypid is: " << getpid() << ", my name is:" << threadName << endl;
        sleep(1);
        cout << endl;
    };
}
// 线程创建
void test1()
{
    // 在main这个进程（主线程）中创建一个新线程
    pthread_t tid;
    // 创建完线程后线程跳转进程ThreadTest函数中
    pthread_create(&tid, nullptr, ThreadTest1, (void *)"Thread one");

    // 主线程
    while (1)
    {
        cout << "my name is Thread main, my pid is: " << getpid() << endl;
        sleep(1);
        cout << endl;
    }
}

typedef function<void()> func_t;

class ThreadData
{
public:
    ThreadData(const string &name, const uint64_t &ctime, func_t f)
        : thread_name(name), creat_time(ctime), func(f)
    {
    }

    string GetName() const { return thread_name; }
    uint64_t GetTime() const { return creat_time; }
    func_t GetFunc() const { return func; }

private:
    string thread_name;
    uint64_t creat_time;
    func_t func;
};
void Print()
{
    cout << "only print……" << endl;
}
void *ThreadTest2(void *arg)
{
    ThreadData *td = (ThreadData *)arg;
    while (1)
    {
        cout << "当前线程名为：" << td->GetName() << "，创建时间为：" << td->GetTime() << endl;
        (td->GetFunc())();
        sleep(1);
    }
}
// 线程函数是可以传对象作为参数的
void test2()
{
    pthread_t tid;
    ThreadData *td = new ThreadData("Thread one", (uint64_t)time(nullptr), Print);

    // 可以传入任意类型的参数
    pthread_create(&tid, nullptr, ThreadTest2, td);

    // 主线程
    while (1)
    {
        cout << "my name is Thread main, my pid is: " << getpid() << endl;
        sleep(3);
        cout << endl;
    }
}

// 创建多线程
void test3()
{
    // 存储多个id
    vector<pthread_t> id_pthreads;

    for (int i = 0; i < 3; i++)
    {
        pthread_t tid;
        id_pthreads.push_back(tid);
        char name[64];
        snprintf(name, sizeof(name), "%s-%lu", "thread", i);

        ThreadData *td = new ThreadData(name, (uint64_t)time(nullptr), Print);
        pthread_create(&tid, nullptr, ThreadTest2, td);
    }
    for (auto &e : id_pthreads)
    {
        cout << e << " ";
    }
    cout << endl;
    while (1)
    {
        // 让主线程不退出
        sleep(1);
    }
}

void *ThreadTest4(void *arg)
{
    ThreadData *td = (ThreadData *)arg;
    while (1)
    {
        cout << "当前线程名为：" << td->GetName() << "，创建时间为：" << td->GetTime() << endl;
        (td->GetFunc())();
        if (td->GetName() == "thread-6")
        {
            cout << "通过kill函数接收到2号信号" << endl;
            kill(getpid(), 2);
        }
        sleep(2);
    }
}
// 测试线程的较弱的健壮性
void test4()
{
    for (int i = 0; i < 7; i++)
    {
        pthread_t tid;
        char name[64];
        snprintf(name, sizeof(name), "%s-%lu", "thread", i);

        ThreadData *td = new ThreadData(name, (uint64_t)time(nullptr), Print);
        pthread_create(&tid, nullptr, ThreadTest4, td);
    }

    while (1)
    {
        // 让主线程不退出
        sleep(1);
    }
}

void *ThreadTest5(void *arg)
{
    const char *threadName = (const char *)arg;

    cout << "i am a new thread, mypid is: " << getpid() << ", my name is:" << threadName << endl;
    sleep(2);

    // 线程终止的方式一: 调用的函数完成

    // exit 会导致整个进程退出，所以不能作为线程终止的方式

    // 方式二: 库中的函数
    // pthread_exit(nullptr);

    // pthread_exit((void*)"hello thread");
}
// 线程退出和线程等待
void test5()
{
    // 在main这个进程（主线程）中创建一个新线程
    pthread_t tid;
    // 创建完线程后线程跳转进程ThreadTest函数中
    pthread_create(&tid, nullptr, ThreadTest5, (void *)"Thread one");

    // pthread_self查看当前线程的id
    cout << "main thread id: " << pthread_self() << endl;
    cout << "new thread id: " << tid << endl;
    sleep(2);
    // thread id本质上就是地址

    // 主线程
    while (1)
    {
        cout << "my name is Thread main, my pid is: " << getpid() << endl;
        sleep(1);
        cout << endl;
    }

    // 线程退出时也是需要被主线程进行等待的
    // 1.需要解决不等待的僵尸问题
    // 2.主线程如何获得子线程的返回值

    // 通过pthread_join()
    // 进行阻塞式等待tid这个线程！
    pthread_join(tid, nullptr);

    // pthread_join跟pthread_exit配套使用，当pthread_exit返回不为空时
    // void *ret = nullptr;
    // pthread_join(tid, &ret);

    // 当然也是可以接收对象的！！！void*的可操作空间非常大

    // 线程不需要接收异常信息，因为线程一旦异常，该进程直接退出
}

void *ThreadTest6(void *arg)
{
    // 也可子线程对自己进行分离，但是写在这里最好
    pthread_detach(pthread_self());
    while (1)
    {
        const char *threadName = (const char *)arg;
        cout << "i am a new thread, mypid is: " << getpid() << ", my name is:" << threadName << endl;
        sleep(2);
    }
}
// 设置可分离的线程，线程的取消
void test6()
{
    // 在test5中，我们只能进行阻塞式等待，但是这时不合理的

    pthread_t tid;
    pthread_create(&tid, nullptr, ThreadTest1, (void *)"Thread one");

    // 线程是可以设置为分离状态，主线程不用对新线程进行等待
    // 可以是主线程对子线程进行分离
    // pthread_detach(tid);

    // 分离后，主线程无法对该线程进行pthread_join
    // 如果主线程对子线程的返回值不关心，或者是并不需要等待

    // 线程是可以取消的---相当于之间终止该线程
    pthread_cancel(tid);

    // cancle后通过pthread_join接收该进程的返回值，会返回-1

    // 但是主线程依旧是最晚退出的！！！
}

int g_val = 100;
__thread int t_val = 0;
void *ThreadFunc(void *arg)
{
    while (1)
    {
        g_val += 10;
        t_val--;
        cout << "new thread g_val = " << g_val << ", t_val = " << t_val << endl;
        sleep(2);
    }
}
// 线程的局部存储
void test7()
{
    pthread_t tid;
    pthread_create(&tid, nullptr, ThreadFunc, (void*)nullptr);

    while(1)
    {
        t_val++;
        g_val = 0;
        cout << "main thread g_val = " << g_val << ", t_val = " << t_val << endl;
        sleep(2);
        cout<<endl;
    }
}

int main()
{
    test7();
}
